package com.palm.vue.compiler;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
/**
 * css代码简单压缩，去掉注释和多余空白
 */
public class CssCompressor {
    private final int EOF = -1;
    private final StringReader inputStream;
    private final StringWriter outputStream;


    private static enum State {
        STATE_FREE, STATE_ATRULE, STATE_SELECTOR, STATE_BLOCK, STATE_DECLARATION, STATE_COMMENT;
    }

    private int theLookahead = EOF;

    private State tmp_state;

    private State state = State.STATE_FREE;

    private State last_state = State.STATE_FREE;

    private boolean in_paren = false;

    public CssCompressor(String css) {
        this.inputStream = new StringReader(css);
        this.outputStream = new StringWriter();
    }

    public String minify() {
        try {
            cssmin();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
        }
        return outputStream.toString();
    }


    /* cssmin -- minify the css
    removes comments
    removes newlines and line feeds keeping
    removes last semicolon from last property
*/
    private void cssmin() throws IOException {
        for (; ; ) {
            int c = get();

            if (c == EOF) {
                return;
            }

            c = machine(c);

            if (c != 0) {
                outputStream.write(c);
            }
        }
    }

    /* get -- return the next character from stdin. Watch out for lookahead. If
the character is a control character, translate it to a space or
linefeed.
*/
    private int get() throws IOException {
        int c = theLookahead;
        theLookahead = EOF;
        if (c == EOF) {
            c = inputStream.read();
        }

        if (c >= ' ' || c == '\n' || c == EOF) {
            return c;
        }

        if (c == '\r') {
            return '\n';
        }

        return ' ';
    }

    /* peek -- get the next character without getting it.
     */

    private int peek() throws IOException {
        theLookahead = get();
        return theLookahead;
    }

    /* machine
     */
    private int machine(int c) throws IOException {

        if (state != State.STATE_COMMENT) {
            if (c == '/' && peek() == '*') {
                tmp_state = state;
                state = State.STATE_COMMENT;
            }
        }

        switch (state) {
            case STATE_FREE:
                if (c == ' ' && c == '\n') {
                    c = 0;
                } else if (c == '@') {
                    state = State.STATE_ATRULE;
                    break;
                } else if (c > 0) {
                    //fprintf(stdout,"one to 3 - %c %i",c,c);
                    state = State.STATE_SELECTOR;
                }
            case STATE_SELECTOR:
                if (c == '{') {
                    state = State.STATE_BLOCK;
                } else if (c == '\n') {
                    c = 0;
                } else if (c == '@') {
                    state = State.STATE_ATRULE;
                } else if (c == ' ' && peek() == '{') {
                    c = 0;
                }
                break;
            case STATE_ATRULE:
			/* support
				@import etc.
				@font-face{
			*/
                if (c == '\n' || c == ';') {
                    c = ';';
                    state = State.STATE_FREE;
                } else if (c == '{') {
                    state = State.STATE_BLOCK;
                }
                break;
            case STATE_BLOCK:
                if (c == ' ' || c == '\n') {
                    c = 0;
                    break;
                } else if (c == '}') {
                    state = State.STATE_FREE;
                    //fprintf(stdout,"closing bracket found in block\n");
                    break;
                } else {
                    state = State.STATE_DECLARATION;
                }
            case STATE_DECLARATION:
                //support in paren because data can uris have ;
                if (c == '(') {
                    in_paren = true;
                }
                if (!in_paren) {

                    if (c == ';') {
                        state = State.STATE_BLOCK;
                        //could continue peeking through white space..
                        if (peek() == '}') {
                            c = 0;
                        }
                    } else if (c == '}') {
                        //handle unterminated declaration
                        state = State.STATE_FREE;
                    } else if (c == '\n') {
                        //skip new lines
                        c = 0;
                    } else if (c == ' ') {
                        //skip multiple spaces after each other
                        if (peek() == c) {
                            c = 0;
                        }
                    }

                } else if (c == ')') {
                    in_paren = false;
                }

                break;
            case STATE_COMMENT:
                if (c == '*' && peek() == '/') {
                    theLookahead = EOF;
                    state = tmp_state;
                }
                c = 0;
                break;
        }

        return c;
    }
}
